package com.sitech.ibnms.c3p.task.notice;

import com.sitech.ibnms.c3p.domain.*;
import com.sitech.ibnms.c3p.mappers.C3pNoticeMapper;
import com.sitech.ibnms.c3p.mappers.C3pScheduleNoticeTimeMapper;
import com.sitech.ibnms.c3p.task.TaskStatus;
import com.sitech.ibnms.c3p.task.listeners.BaselineWarningListener;
import com.sitech.ibnms.c3p.task.listeners.TaskCompleteListener;
import com.sitech.ibnms.c3p.task.listeners.TaskFailedListener;
import com.sitech.ibnms.c3p.task.listeners.TaskWarningListener;
import com.sitech.ibnms.c3p.util.C3pConstants;
import com.sitech.ismp.workflow.domain.ProcessInstance;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * Created by liujhc on 11/4.
 */
@Component
public class NoticeTaskListener implements TaskFailedListener, TaskCompleteListener, TaskWarningListener, BaselineWarningListener {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private C3pNoticeMapper c3pNoticeMapper;
    @Autowired
    private NoticeService noticeService;
    @Autowired
    private C3pScheduleNoticeTimeMapper noticeTimeMapper;

    @Override
    public void onFailed(C3pTask c3pTask, ProcessInstance processInstance, String failReason) throws Exception {
        logger.info("onFailed: serialNo={}, {}", processInstance.getSerialNo(), c3pTask);
        String messageContent = String.format("任务【%s】执行失败，流程实例号为[%s], 启动时间[%s], 失败原因：%s",
                c3pTask.getTaskName(), processInstance.getSerialNo(),
                DateFormatUtils.format(processInstance.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), failReason);
        sendNotice(c3pTask, processInstance, TaskStatus.FAILED, messageContent);
    }

    @Override
    public void onComplete(C3pTask c3pTask, ProcessInstance processInstance) throws Exception {
        logger.info("onComplete: serialNo={}, {}", processInstance.getSerialNo(), c3pTask);
        String messageContent = String.format("任务【%s】执行成功，流程实例号为[%s], 启动时间为[%s]",
                c3pTask.getTaskName(), processInstance.getSerialNo(),
                DateFormatUtils.format(processInstance.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
        sendNotice(c3pTask, processInstance, TaskStatus.COMPLETE, messageContent);
    }

    @Override
    public void onWarning(C3pTask c3pTask, ProcessInstance processInstance, C3pExecNotice execNotice) throws Exception {
        logger.info("onWarning: serialNo={}, {}", processInstance.getSerialNo(), c3pTask);
        sendNotice(c3pTask, processInstance, TaskStatus.WARNING, execNotice.getNoticeContent());
    }

    @Override
    public void onBaselineWarning(C3pTask c3pTask, ProcessInstance processInstance, C3pExecNotice execNotice) throws Exception {
        logger.info("onBaselineWarning: serialNo={}, {}", processInstance.getSerialNo(), c3pTask);
        sendNotice(c3pTask, processInstance, TaskStatus.BASELINE_WARNING, execNotice.getNoticeContent());
    }

    private boolean isScheduledTask(String scheduleId) {
        return scheduleId != null && scheduleId.length() > 20;
    }

    private void sendNotice(C3pTask c3pTask, ProcessInstance processInstance, TaskStatus taskStatus, String... noticeContents) throws Exception {
        String scheduleId = processInstance.getWf_num();
        int execId = processInstance.getSerialNo();
        if (logger.isInfoEnabled()) {
            logger.info("NoticeContents:\n{}", StringUtils.join(noticeContents, '\n'));
        }
        if (isScheduledTask(scheduleId)) { // 判断是否在设置的发送时间段内
            List<C3pScheduleNoticeTime> noticeTimes = noticeTimeMapper.findByScheduleId(scheduleId);
            String now = DateFormatUtils.format(System.currentTimeMillis(), "HH:mm:ss");
            boolean isInNoticeTime = noticeTimes.isEmpty();
            StringBuilder logging = new StringBuilder();
            for (C3pScheduleNoticeTime noticeTime : noticeTimes) {
                String beginTime = DateFormatUtils.format(noticeTime.getBeginTime(), "HH:mm:ss");
                String endTime = DateFormatUtils.format(noticeTime.getEndTime(), "HH:mm:ss");
                logging.append(",").append(beginTime).append("-").append(endTime);
                if (now.compareTo(beginTime) > 0 && now.compareTo(endTime) < 0) {
                    isInNoticeTime = true;
                    break;
                }
            }
            if (!isInNoticeTime) {
                logger.info("当前时间不在设置的发送时间段内[{}]，跳过发送逻辑。 {c3pTaskId={}, execId={}, scheduleId={}}",
                        logging.substring(1), c3pTask.getTaskId(), execId, scheduleId);
                return;
            }
        }
        List<C3pNotice> c3pNotices = c3pNoticeMapper.findByC3pTaskIdAndStatus(c3pTask.getTaskId(), taskStatus);
        String messageContent = noticeContents[0];
        Set<String> mailedAddresses = new HashSet<String>();
        logger.info("c3pNotices: {}", c3pNotices);
        for (C3pNotice c3pNotice : c3pNotices)
            try {
                switch (NoticeType.valueOf(c3pNotice.getNoticeType())) {
                    case MAIL:
                        List<String> mailContentList = getMailContentByNotice(c3pTask.getTaskId(), processInstance, c3pNotice.getNoticeId());
                        for (String addr : StringUtils.split(c3pNotice.getNoticeAddr(), ',')) {
                            logger.info("ExecId[{}] send mail to {}:{}", execId, addr, messageContent);
                            if (mailedAddresses.contains(addr)) continue;
                            TbSubscribeMail mail = new TbSubscribeMail(execId + UUID.randomUUID().toString().substring(8), addr, messageContent);
                            noticeService.sendMail(mail, mailContentList);
                            mailedAddresses.add(addr);
                        }
                        break;
                    case SMS:
                        for (String addr : StringUtils.split(c3pNotice.getNoticeAddr(), ',')) {
                            logger.info("ExecId[{}] send sms to {}:{}", execId, addr, messageContent);
                            noticeService.sendMessage(addr, execId, messageContent);
                        }
                        break;
                }
            } catch (Throwable e) {
                logger.error(e.getMessage(), e);
            }
        // 通知任务执行人
        int notifyFlag = processInstance.getTitle().charAt(0);
        if ((notifyFlag & C3pConstants.FLAG_MAIL_NOTIFY) == C3pConstants.FLAG_MAIL_NOTIFY) {
            //查询用户邮箱
            String userEmail = c3pNoticeMapper.selectEmailByUserId(processInstance.getCreater());
            if (!mailedAddresses.contains(userEmail)) {
                logger.info("send MAIL to creator: serialNo={}, {}", processInstance.getSerialNo(), c3pTask);
                TbSubscribeMail mail = new TbSubscribeMail(execId + UUID.randomUUID().toString().substring(8), userEmail, messageContent);
                noticeService.sendMail(mail, getMailContentByNotice(c3pTask.getTaskId(), processInstance, null));
            }
        }
        if ((notifyFlag & C3pConstants.FLAG_SMS_NOTIFY) == C3pConstants.FLAG_SMS_NOTIFY) {
            logger.info("send SMS to creator: serialNo={}, {}", processInstance.getSerialNo(), c3pTask);
            noticeService.sendMessage(processInstance.getCreater(), execId, messageContent);
        }
    }

    @Cacheable("instant")
    private List<String> getMailContentByNotice(String c3pTaskId, ProcessInstance processInstance, String noticeId) {
        String lineSeparator = "\n";
        try {
            String completeMail = noticeService.getCompleteMail(c3pTaskId, processInstance, noticeId);
            return Arrays.asList(completeMail.split(lineSeparator));
        } catch (Exception e) {
            logger.warn("Failed to parse Mail Content:", e);
            return Arrays.asList(("解析报告模板失败，失败原因：\n" + e.getMessage()).split(lineSeparator));
        }
    }
}
